/**
 * Copyright (C) 2013 Daniel Gee.
 * See LICENSE.txt for more details.
 */
package com.rl.util;

import java.io.Serializable;
import java.util.EnumMap;

/**
 * Many thanks to <a href="http://stackoverflow.com/users/1350762/maba">Maba</a> on Stack Overflow
 * for explaining how to design this thing as a generic.
 * 
 * <p>
 * This class is like a {@link java.util.EnumMap}, but for ints. You would use it any place that
 * you'd want to have an int stored for one or more Enum instances of the same Enum as a group. For
 * example, if the creature stats in your game or item stats in your game were Enums, each creature
 * or item could use one of these to store their values.
 * </p>
 * 
 * <p>
 * Note that this class uses the {@link Enum#ordinal()} method to store values internally, so even
 * though it's {@link Serializable}, it depends upon the exact ordinal of the associated enum to be
 * usefully serialized and deserialized. If you want <i>completely</i> safe Serialization, you can
 * use an {@link EnumMap}<tt>&lt;E,Integer&gt;</tt> to get most of the same effects of this class.
 * However, that does require some autoboxing. That's why I wrote this class in the first place, to
 * bypass all that autoboxing stuff.
 * </p>
 * 
 * @author Daniel Gee
 * @param <E>
 *            the type of Enum this instance will be mapping values for.
 */
public class EnumIntMap<E extends Enum<E>> implements Serializable
{
	/**
	 * for serialization.
	 */
	private static final long serialVersionUID = 8532994474335802833L;

	/**
	 * The data we're storing.
	 */
	private final int[] values;

	/**
	 * Constructs a new instance keyed to a particular Enum.
	 * 
	 * @param cls
	 *            the class of the Enum that's being used to map out values.
	 */
	public EnumIntMap(Class<E> cls)
	{
		this.values = new int[cls.getEnumConstants().length];
	}

	/**
	 * Obtains the value associated with the instance given.
	 * 
	 * @param a
	 *            the Enum instance to get the value for.
	 * @return the value mapped to that instance.
	 */
	public int getValue(E a)
	{
		return this.values[a.ordinal()];
	}

	/**
	 * Modifies all values by the specified amount.
	 * 
	 * @param amount
	 *            the amount to increase or decrease the existing value by.
	 */
	public void modifyAll(int amount)
	{
		for (int i = 0; i < this.values.length; i++)
		{
			this.values[i] += amount;
		}
	}

	/**
	 * Modifies the given trait by the amount specified.
	 * 
	 * @param a
	 *            the trait to modify.
	 * @param amount
	 *            the amount to increase or decrease the existing value by.
	 */
	public void modifyValue(E a, int amount)
	{
		this.values[a.ordinal()] += amount;
	}

	/**
	 * Assigns the value of all instances to be the value given.
	 * 
	 * @param value
	 *            the value to set.
	 */
	public void setAll(int value)
	{
		for (int i = 0; i < this.values.length; i++)
		{
			this.values[i] = value;
		}
	}

	/**
	 * Assigns the value to associate with the instance given.
	 * 
	 * @param a
	 *            the Enum instance to set the value for.
	 * @param value
	 *            the value to set.
	 */
	public void setValue(E a, int value)
	{
		this.values[a.ordinal()] = value;
	}
}